

	/********************************************************/
	/*                                                      */
	/*                                                      */
	/*         Copyright (C), 1993  SEIKO EPSON Corp.       */
	/*         ALL RIGHTS RESERVED                          */
	/*                                                      */
	/*                                                      */
	/*  file name : _doprint.c                              */
	/*                                                      */
	/*  Revision history                                    */
	/*      93/12/17    first release       K.Shinozuka     */
	/*	97/3/25		M.Kudo                          */
	/*      99/11/05    bug fix for round off and %f        */
	/*                  exponential data    T.Mineshima     */
	/*	01/3/26	    %f bug fix		T.Tazaki        */
	/*                                                      */
	/********************************************************/


/* Please read the comment of _doprint about the function of _doprint. */

/* ALGORITHM
 *
 * 1. get the output format and store the data in the data structure
 * 2. convert a argument to a string according to the data structure
 * 3. a string may be divided three parts ( sign / string A / string B ) as following.
 *    set each number of characters in the string ( n0 / n1 / n2 ) in the data structure
 *
 *                         store pointer
 *    start of             start of the main part of the string
 *      store array        |
 *                |        | 
 *                |        |        
 *                |  sign  |  string A        string B    
 *    converted   |        |
 *      string     -------------------------------------
 *                |   n0   |     n1       |     n2      |
 *                 -------------------------------------
 *                         ^              ^             ^
 *                         0              0             0      ..... zero padding
 *                        np1            np2           np3           length of zero padding
 *
 *    string        data                   conversion
 *     sign   : sign ( +, space, - )     d, i, e, E, f, g, G 
 *              prefix ( 0, 0x, 0X )        o, x, X
 *              character                       c
 *              no data                         s
 *   string A : integral number          d, i, o, u, x, X
 *              fractional part             e, E, g, G
 *              integral part            f     ( argument is equal or greater then 1.0 )
 *                "0."                   f     ( argument is less than 1.0 )
 *              string                   s  ( string is not stored in store array,
 *                                            but store pointer is set to point to the string )
 *   string B : exponential part            e, E, g, G
 *              decimal part                     f          
 *              no data                   c, s, d, i, x, X
 *
 * 4. set the numbers of 0 padding between sign and string A ( np1 ), string A and string B,
 *    ( np2 ) or after string B ( np3 )         
 *    np1 will be set when 0 flag is specified.
 *    np2 is for too big value or the value less than 0.1 in case of f conversion,
 *      or for precision of exponential notation. ( e, E, g, G conversion )
 *    np3 is needed when value of precision is too big in case of f conversion.
 *
 *      example        string          conversion   n0  np1 n1  np2 n2  np3
 *                 +|000|123|              d         1   3   3   0   0   0
 *                 1.2345|00|e+111         e         0   0   6   2   5   0
 *                 -|123|0000|.|00000      f         1   0   3   4   1   5
 *                 123|.04567|0            f         0   0   3   0   6   1
 *                 0.|000|12345|000        f         0   0   2   3   5   3
 *
 * 5. set the numbers of leading and trailing spaces in the field
 *    If the amount of characters of converted string and padding 0 is less than minimum
 *    field width, some spaces will be padded before or after the string to fill the field.
 *    The number of leading spaces is np0 and that of trailing spaces is np4.  
 *    At least one of them must be zero.
 * 6. put the string to the destination
 *         np0   characters of     spaces
 *         n0    characters of     sign string
 *         np1   characters of     0
 *         n1    characters of     string A
 *         np2   characters of     0
 *         n2    characters of     string B
 *         np3   characters of     0
 *         np4   characters of     spaces
 * 7. continue from 1 to 6 while end of format string is not reached
 *
 */



#ifdef	UNIX
#include    "stdio.h"
#include    "smcvals.h"
#include    "stdarg.h"
#include    "string.h"
#include    "math.h"
#include    "ctype.h"
#include    "errno.h"
#include    "float.h"
#else
#include    <stdio.h>
#include    <smcvals.h>
#include    <stdarg.h>
#include    <string.h>
#include    <math.h>
#include    <ctype.h>
#include    <errno.h>
#include    <float.h>
#endif


#define _PHI      'H'
#define _PLO      'L'
#define _PPLUS    '+'             /* +flag is specified */
#define _PSPAC    ' '             /* space flag is specified */
#define _PSHRT    'h'             /* short size is specified */
#define _PLONG    'l'             /* long size is specified  */
#define _STRSIZ   32              /* maximum size of output string */
#define _PAD_MAX  20              /* size of padding string */
#define _INT_NUM  24              /* bigger number than the digit of unsigned long int */


extern unsigned char *_ptrans(  /* _PDAT *, unsigned char * */            );
extern void           _pint(    /* _PDAT *, unsigned long, int, char * */ );
extern void           _pfloat(  /* _PDAT *, double, char *  */            );
extern int            _pfrtoch( /* double, int *, int, char * */          );

typedef int _PFLGTYP;

typedef struct tgPDat {           /*                  data   structure                        */
	    va_list        tdArgP;    /* the list of a variable number of arguments */
	    _PFLGTYP       tdPosFlg;  /* position flag
	                                 _PHI ( left-justification ) / _PLO ( right-justification ) */
	    _PFLGTYP       tdSigFlg;  /* sign flag
	                                 _PPLUS ( + ) / _PSPAC ( space ) / _PLO ( not specified ) */
	    _PFLGTYP       tdPadFlg;  /* padding ( 0 ) flag
	                                 _PHI ( 0 padding ) / _PLO ( not specified ) */
	    _PFLGTYP       tdBasFlg;  /* form ( # ) flag
	                                           _PHI ( specified ) / _PLO ( not specified ) */
	    _PFLGTYP       tdSiz;     /* size of argument */
	    int            iWid;      /* the minimum field width */
	    int            iPrec;     /* precise */
	    unsigned char *ucOutDatP; /* store address of main part of converted string */
	    int            iHeadPad;  /* np0, the number of spaces at the head of the field */
	    int            iSigPad;   /* npi, the number of 0-paddings by 0 flag */ 
	    int            iFltPad;   /* np2, the number of 0-paddings at floating type  */ 
	    int            iPrecPad;  /* np3, the number of 0-paddings for precise  */ 
	    int            iTailPad;  /* np4, the number of spaces at the end of the field */
	    int            iSigNum;   /* n0,  the length of the string for sign/prefix/character/% */
	    int            iDatNum;   /* n1,  the length of the string for the main part of
	                                                               int/float/string conversion */
	    int            iExpNum;   /* n2,  the length of the string for exponential/decimal part */
	 } _PDAT;



    /********************************************************/
    /*                                                      */
    /*  _PAD( cPadStrP, iChNum )                            */
    /*   char *cPadStrP; pointer to the padding array,      */
    /*                    CSpace[ ] (for space padding) or  */
    /*                    CZero[ ] (for 0 padding)          */
    /*   int  iChNum   ; number of padding characters       */
    /*                                                      */
    /*   function:                                          */
    /*     This macro function pads iChNum characters to    */
    /*     the stream or string, from the string pointed to */
    /*     by cPadStrP.                                     */
    /*                                                      */
    /********************************************************/

#define _PAD( cPadStrP, iChNum )      \
	             for( iCnt = iChNum; iCnt > _PAD_MAX; iCnt = iCnt - _PAD_MAX) {   \
	                _PUT( cPadStrP, _PAD_MAX );  \
	             }  \
	             _PUT( cPadStrP, iCnt );


    /********************************************************/
    /*                                                      */
    /*  _PUT( ucPutStrP, iChNum )                           */
    /*   char *cPadStrP; pointer to the string to be put out*/
    /*   int  iChNum   ; number of output characters        */
    /*                                                      */
    /*   function:                                          */
    /*     This macro function puts iChNum characters to    */
    /*     the stream or string, from the string pointed to */
    /*     by ucPutStrP.                                    */
    /*     And count up the number of outputs character.    */
    /*                                                      */
    /********************************************************/

#define _PUT( ucPutStrP, iChNum )     \
	             if( tdCode == _STRM ) {  \
	                if( write( fiStrmP->_fd, ucPutStrP, iChNum ) != iChNum ) {  \
	                   return( EOF );   \
	                }  \
	             } else {  \
	                memcpy( ucDestP, ucPutStrP, iChNum );  \
	                ucDestP = ucDestP + iChNum;  \
	             }  \
	             iOutChNum = iOutChNum + iChNum;
	             



int
_doprint( tdCode, ucDestP, ucFmtP, tdApP )

	/********************************************************/
	/*                                                      */
	/*  The _doprint function converts the variable numbers */
	/*  of argument to a string under control of the output */
	/*  format ( ucFmtP ), and put it out to the destination*/
	/*  pointed to by ucDestP.                              */
	/*  ucDestP is the file stream ( the case tdSCode is    */
	/*  "_STRM" ) or pointer to a string ( tdScode is       */
	/*  "_STR" ).                                           */
	/*  The format is composed of zero or more directives;  */
	/*  ordinary single byte characters ( not % ), which    */
	/*  are copied to the output stream; and conversion     */
	/*  specifications, each of which is started with the   */
	/*  character %.                                        */
	/*  About the specification of the conversion, please   */
	/*  read READMEstdio.                                   */
	/*  The doprint function returns when the end of the    */
	/*  format string is reached or output error occurs.    */
	/*  If the format is exhausted while arguments remain,  */
	/*  the excess arguments are evaluated but not          */
	/*  converted.                                          */
	/*                                                      */
	/*      RETURN  except EOF ... the number of characters */
	/*                             transmitted              */
	/*              EOF        ... output failure           */
	/*                                                      */
	/********************************************************/

    _CODETYP tdCode          ;   /* type of output source  _STRM (stream) / _STR (string) */
    unsigned char  *ucDestP  ;   /* pointer to output source */
    unsigned char  *ucFmtP   ;   /* pointer to output format */
    va_list         tdApP    ;   /* pointer to the list of variable numbers of argument */

    {
	 _PDAT          stDat    ;   /* data structure, hold conversion data */
	 int            iOutChNum;   /* the number of characters transmitted */
	 int            iCnt     ;   /* counter used in macro function _PAD */
	 int            iOutNum  ;   /* the number of characters putted out directory */
	 FILE          *fiStrmP  ;   /* output stream */
	 _PFLGTYP       tdEndFlg ;   /* flag to check the end of setting of flag */
	 unsigned char *ucFmtChP ;   /* pointer to access the format string */
	 unsigned char  UcOutStr[ _STRSIZ ]; /* the array converted string will be stored */
	 const static char CSpace[ ] = "                    "; /* space * 20 characters for space padding */
	 const static char CZero[ ] = "00000000000000000000" ; /* zero * 20 characters for zero padding */


	 /* initialize */
	 stDat.tdArgP = tdApP;              /* variable argument */
	 iOutChNum = 0;                     /* number of output characters */
	 iOutNum = 0;
	 fiStrmP = (FILE *)ucDestP;         /* file stream */ 

	 /* conversion and output */
	 while( ucFmtP != '\0' ) {          /* not end of output format */

	 /* direct output */
	    ucFmtChP = ucFmtP;              /* set the first character to be converted */
	    iOutNum = 0;
	    while( (*ucFmtChP != '%') && (*ucFmtChP != '\0') ) {
	                                    /* not conversion start sign nor end of format */
	       ++ucFmtChP;
	       ++iOutNum;
	    }
	    _PUT( ucFmtP, iOutNum );

	 /* conversion */
	    if( *ucFmtChP == '%' ) {        /* start of conversion */

	 /* setting flags */
	       stDat.tdPosFlg = _PLO;       /* - flag is not specified */ 
	       stDat.tdSigFlg = _PLO;       /* +/space flag is not specified */ 
	       stDat.tdPadFlg = _PLO;       /* 0 flag is not specified */ 
	       stDat.tdBasFlg = _PLO;       /* # flag is not specified */ 
	       tdEndFlg = _PLO;             /* setting of flag is not completed */

	       do {
	          ++ucFmtChP;
	          switch( *ucFmtChP ) {
	             case '-':
	                stDat.tdPosFlg = _PHI;
	                break;
	             case '+':
	                stDat.tdSigFlg = _PPLUS;
	                break;
	             case ' ':
	                if( stDat.tdSigFlg == _PLO ){  /* If space and + both appear, */
	                   stDat.tdSigFlg = _PSPAC;    /*    space will be ignored.  */
	                }
	                break;
	             case '0':
	                stDat.tdPadFlg = _PHI;
	                break;
	             case '#':
	                stDat.tdBasFlg = _PHI;
	                break;
	             default :
	                tdEndFlg = _PHI;
	                break;
	          }
	       } while( tdEndFlg == _PLO );    /* setting of flag is not completed */

	 /* setting minimum field width */
	       if( *ucFmtChP != '*' ) {        /* not specified by argument */
	          for( stDat.iWid = 0; isdigit( *ucFmtChP ); ++ucFmtChP ) {
	             stDat.iWid = stDat.iWid * 10 + *ucFmtChP - '0';
	          }
	       } else {
	          stDat.iWid = va_arg( stDat.tdArgP, int );
	          if( stDat.iWid < 0 ) {       /* If the value of argument is negative, */
	                                       /* it means - flag and the absolute value */
	                                       /* for minimum field width. */
	             stDat.tdPosFlg = _PHI;
	             stDat.iWid = -stDat.iWid;
	          }
	          ++ucFmtChP;
	       }

	 /* setting precision */
	       if( *ucFmtChP != '.' ) {        /* precision is not specified */
	          stDat.iPrec = -1;            /* not specified */
	       } else {
	          ++ucFmtChP;
	          if( *ucFmtChP != '*' ) {     /* not specified by argument */ 
	             for( stDat.iPrec = 0; isdigit( *ucFmtChP ); ++ucFmtChP ) {
	                stDat.iPrec = stDat.iPrec * 10 + *ucFmtChP - '0';
	             }
	          } else {
	             stDat.iPrec = va_arg( stDat.tdArgP, int );
	             ++ucFmtChP;
	          }
	       }

	 /* setting the size of argument */
	       if( *ucFmtChP == 'h' ) {        /* short size */
	          stDat.tdSiz = _PSHRT;
	          ++ucFmtChP;
	       } else if( *ucFmtChP == 'l' ) { /* long size */
	          stDat.tdSiz = _PLONG;
	          ++ucFmtChP;
	       } else {
	          stDat.tdSiz = _PLO;
	       }

	 /* conversion */
	       ucFmtP = _ptrans( &stDat, ucFmtChP, UcOutStr );

	 /* put converted string out */
	       _PAD( CSpace, stDat.iHeadPad );         /* spaces at the head of the field */
	       _PUT( UcOutStr, stDat.iSigNum );        /* sign/prefix/character/'%' */
	       _PAD( CZero, stDat.iSigPad );           /* 0 by 0 flag */
	       _PUT( stDat.ucOutDatP, stDat.iDatNum ); /* int/float/string */
	       _PAD( CZero, stDat.iFltPad );           /* 0 for floating number */
	       _PUT( stDat.ucOutDatP + stDat.iDatNum, stDat.iExpNum );
	                                               /* exponential/decimal part */
	       _PAD( CZero, stDat.iPrecPad );          /* 0 for precision of float conversion */
	       _PAD( CSpace, stDat.iTailPad );         /* spaces at the end of the field */

	    } else {                           /* end of output format */
	       break;
	    }
	 }

	 return( iOutChNum );
	}




unsigned char *
_ptrans( stDatP, ucFmtP, ucOutStrP )

    /********************************************************/
    /*                                                      */
    /*  The _ptrans function converts an argument to a      */
    /*  string, under control of data structure pointed to  */
    /*  by stDatP.                                          */
    /*  The string will be stored in the address pointed to */
    /*  by ucOutStrP except s-conversion.  And the pointer  */
    /*  to the main part of converted string ( ucOutDatP,   */
	/*  a member of data structure stDatP ) will be set to  */
	/*  the next to 'sign' string ( string A ), or to the   */
	/*  first character of the string ( in case of          */
	/*  s-conversion ).                                     */
    /*  The numbers of each part of converted string and of */
    /*  padding characters will be also set.  ( n0 ~ n2 ,   */
    /*  np0 ~ np4 )                                         */
    /*                                                      */
    /*      RETURN  pointer to the next character of        */
    /*              the output format                       */
    /*                                                      */
    /********************************************************/

	_PDAT          *stDatP   ;   /* data structure */
	unsigned char  *ucFmtP   ;   /* pointer to output format */
	unsigned char  *ucOutStrP;   /* pointer to an array, 
	                                    converted string will be stored in */

    {
	 int            iBase    ;   /* base of unsigned integer */
	 long           lArg     ;   /* long int argument */
	 unsigned long  ulArg    ;   /* unsigned long argument */
	 DBL_LNG        tdArg    ;   /* double argument */

	 /* initialize the number of output characters */
	 stDatP->iHeadPad = 0;        /* np0 */
	 stDatP->iSigNum = 0;         /* n0 */
	 stDatP->iSigPad = 0;         /* np1 */
	 stDatP->iDatNum = 0;         /* n1 */
	 stDatP->iFltPad = 0;         /* np2 */
	 stDatP->iExpNum = 0;         /* n2 */
	 stDatP->iPrecPad = 0;        /* np3 */
	 stDatP->iTailPad = 0;        /* np4 */

	 /* conversion */
	 switch( *ucFmtP ) {                         /* switch by a conversion specifier */

	 /* conversion of a character */
	    case 'c':
	       *ucOutStrP = va_arg( stDatP->tdArgP, char );
	       stDatP->ucOutDatP = ucOutStrP + 1;
	       stDatP->iSigNum = 1;                  /* n0 */
	       break;

	 /* conversion of a string */
	    case 's':
	       stDatP->ucOutDatP = (unsigned char *)va_arg( stDatP->tdArgP, char * );
	                                             /* set the pointer to argument string */
	       stDatP->iDatNum = strlen( (char *)stDatP->ucOutDatP );
	       if( (stDatP->iPrec >= 0 ) && (stDatP->iPrec < stDatP->iDatNum) ) {
	                                             /* the precision is less then string length */
	          stDatP->iDatNum = stDatP->iPrec;
	       }
	       break;

	 /* conversion of a signed integer */
	    case 'd': case 'i':
	       switch( stDatP->tdSiz ) {             /* switch by size of argument */
	          case _PLONG:                       /* long int */
	             lArg = va_arg( stDatP->tdArgP, long );
	             break;
	          case _PSHRT:                       /* short int */
	             lArg = va_arg( stDatP->tdArgP, short );
	             break;
	          default:                           /* int */
	             lArg = va_arg( stDatP->tdArgP, int );
	             break;
	       }

	       if( lArg >= 0 ) {                     /* argument is positive integer */
	          switch( stDatP->tdSigFlg ) {       /* switch by sign flag */
	             case _PPLUS:                    /* + flag */
	                ucOutStrP[ 0 ] = '+';
	                stDatP->iSigNum = 1;         /* n0 */
	                break;
	             case _PSPAC:                    /* space flag */
	                ucOutStrP[ 0 ] = ' ';
	                stDatP->iSigNum = 1;
	                break;
	             default:
	                break;
	          }
	       } else {
	          ucOutStrP[ 0 ] = '-';
	          stDatP->iSigNum = 1;
	          lArg = -lArg;
	       }

	       stDatP->ucOutDatP = &ucOutStrP[ stDatP->iSigNum ];
	                                             /* set the pointer to main part of string */
	       _pint( stDatP, (unsigned long)lArg, 10, ucFmtP );   /* conversion */
	       break;

	 /* conversion of a unsigned integer */
	    case 'o': case 'u': case 'x': case 'X':
	       switch( stDatP->tdSiz ) {             /* switch by size of argument */
	          case _PLONG:                       /* unsigned long int */
	             ulArg = va_arg( stDatP->tdArgP, long );
	             break;
	          case _PSHRT:                       /* unsigned short int */
	             ulArg = va_arg( stDatP->tdArgP, short );
	             break;
	          default:                           /* unsigned int */
	             ulArg = va_arg( stDatP->tdArgP, int );
	             break;
	       }

	       if( stDatP->tdBasFlg == _PHI ) {      /* # flag is specified */
	          if( *ucFmtP != 'u' ) {             /* prefix is needed */
	             ucOutStrP[ stDatP->iSigNum ] = '0';
	             stDatP->iSigNum += 1;           /* n0 */
	             if( *ucFmtP != 'o' ) {          /* hexadecimal conversion */
	                ucOutStrP[ stDatP->iSigNum ] = *ucFmtP;  /* x or X */
	                stDatP->iSigNum += 1;
	             }
	          }
	       }

	       stDatP->ucOutDatP = &ucOutStrP[ stDatP->iSigNum ];
	                                             /* set the pointer to main part of string */
	       switch( *ucFmtP ) {                   /* switch by a conversion specifier */
	          case 'o':                          /* octal conversion */
	             iBase = 8;
	             break;
	          case 'u':                          /* decimal conversion */
	             iBase = 10;
	             break;
	          default:                           /* hexadecimal conversion */
	             iBase = 16;
	             break;
	       }

	       _pint( stDatP, ulArg, iBase, ucFmtP );/* conversion */
	       break;
	 
	 /* conversion of a floating point number */
	    case 'e': case 'E': case 'f': case 'g': case 'G':
	       tdArg._D = va_arg( stDatP->tdArgP, double );
	       if( ( tdArg.st._LL & NEG_ZERO_L ) == 0 ) {    /* sign bit is 0 */
	          switch( stDatP->tdSigFlg ) {       /* switch by sign flag */
	             case _PPLUS:                    /* + flag */
	                ucOutStrP[ 0 ] = '+';
	                stDatP->iSigNum = 1;         /* no */
	                break;
	             case _PSPAC:                    /* space flag */
	                ucOutStrP[ 0 ] = ' ';
	                stDatP->iSigNum = 1;         /* no */
	                break;
	             default:
	                break;
	          }
	       } else {
	          ucOutStrP[ 0 ] = '-';
	          stDatP->iSigNum = 1;               /* no */
	          tdArg.st._LL = tdArg.st._LL & ( ~NEG_ZERO_L ); /* reset sign bit */
	       }

	       stDatP->ucOutDatP = &ucOutStrP[ stDatP->iSigNum ];
	                                             /* set the pointer to main part of string */

	       switch( *ucFmtP ) {                   /* switch by conversion specifier */
	          case 'g':
	             *ucFmtP = 'e';                  /* g conversion is same as e conversion */
	             break;
	          case 'G':
	             *ucFmtP = 'E';                  /* G conversion is same as E conversion */
	             break;
	          default:
	             break;
	       }
	       if( stDatP->iPrec < 0 ) {             /* check the value of precision */
	          stDatP->iPrec = 6;                 /* default value */
	       }
	       _pfloat( stDatP, tdArg._D, ucFmtP );  /* conversion */
	       break;

	 /* conversion of % */
	    case '%':
	       *ucOutStrP = '%';
	       stDatP->ucOutDatP = ucOutStrP + 1;
	       stDatP->iSigNum = 1;                  /* n0 */
	       break;

	 /* not conversion specifier */
	    default:
	       *ucOutStrP = *ucFmtP;                 /* put a wrong character out directory */
	       stDatP->iSigNum = 1;                  /* no */
	       stDatP->iWid = 0;                     /* reset minimum field width */
	       break;
	 }

	 /* set the number of space padding */
	 stDatP->iWid = (stDatP->iWid) - (stDatP->iSigNum) - (stDatP->iSigPad)
	                 - (stDatP->iDatNum) - (stDatP->iFltPad) - (stDatP->iExpNum)
	                 - (stDatP->iPrecPad);
	 if( stDatP->iWid > 0 ) {                    /* the number of output characters 
	                                                  is less than minimum field width */
	    if( stDatP->tdPosFlg == _PLO ) {         /* right justification */
	       stDatP->iHeadPad = stDatP->iWid;      /* np0 */
	    } else {                                 /* lest justification */
	       stDatP->iTailPad = stDatP->iWid;      /* np3 */
	    }
	 }

	 return( ucFmtP + 1 );
	}



void
_pint( stDatP, ulArgVal, iBase, ucFmtP )

    /********************************************************/
    /*                                                      */
    /*  The _pint function converts unsigned long value to  */
    /*  a string with the base of iBase.                    */
    /*  The string will be stored in the address pointed to */
    /*  by  ucOutDatP, a member of the data structure.      */
    /*  Length of the string ( n1 ) and the number of       */
    /*  padding 0 ( np1 ) will be also set.                 */
    /*                                                      */
    /*      RETURN  non                                     */
    /*                                                      */
    /********************************************************/

	_PDAT          *stDatP   ;   /* data structure */
	unsigned long   ulArgVal ;   /* integer to be converted to a string */
	int             iBase    ;   /* the base of the integer */
	unsigned char  *ucFmtP   ;   /* specifier of the conversion */

	{
	 char          *cDigStrP ;   /* pointer to digit array */
	 int            iStorPos ;   /* index to access array for conversion */
	 char           CIntStr[ _INT_NUM ];  /* array for converted string */
	 const static char    CSmlDig[ ] = "0123456789abcdef"; /* digit array of small letter */
	 const static char    CBigDig[ ] = "0123456789ABCDEF"; /* digit array of capital letter */

	 if( *ucFmtP == 'X' ) {                      /* X conversion */
	    cDigStrP = CBigDig;                      /* use capital letter */
	 } else {
	    cDigStrP = CSmlDig;                      /* use small letter */
	 }

	 iStorPos = _INT_NUM;                        /* set index to the end of the array */
	 do {	                                     /* conversion */
	    --iStorPos;
	    CIntStr[ iStorPos ] = cDigStrP[ ulArgVal % iBase ]; /* set the least digit */
	    ulArgVal  = ulArgVal / iBase;            /* shift to the right */
	 } while( ( ulArgVal > 0 ) && ( iStorPos > 0 ) ); /* there is a digit to be converted */
	 stDatP->iDatNum = _INT_NUM - iStorPos;      /* n1 */
	 memcpy( stDatP->ucOutDatP, &CIntStr[ iStorPos ], stDatP->iDatNum );
	                                             /* copy string to the position of string A */

	 if( stDatP->iPrec > 0 ) {                   /* precision is specified */
	    if( stDatP->iPrec > stDatP->iDatNum ) {  /* precision is bigger than the length of string A */
	       stDatP->iSigPad = stDatP->iPrec - stDatP->iDatNum;
	                                             /* set no, fill with 0 */
	    }
	 } else if( stDatP->iPrec == 0 ) {           /* precision is 0 */
	    if( *(stDatP->ucOutDatP) == '0' ) {      /* argument is 0 */
	       stDatP->iDatNum = 0;
	    }
	 } else {
	    if( (stDatP->tdPadFlg == _PHI) && (stDatP->tdPosFlg == _PLO) 
	          && (stDatP->iWid > (stDatP->iDatNum + stDatP->iSigNum)) ) {
	                                             /* need to fill the field with 0 */
	       stDatP->iSigPad = (stDatP->iWid) - (stDatP->iDatNum) - (stDatP->iSigNum);
	                                             /* np1 */
	    }
	 }
	}




void
_pfloat( stDatP, dDat, cFmtP )

    /********************************************************/
    /*                                                      */
    /*  The _pfloat function converts double size value to  */
    /*  a string.  The string consists of string A ( length */
    /*  n1 ) and string B ( length n2 ).                    */
    /*  The string will be stored in the address pointed to */
    /*  by  ucOutDatP, a member of the data structure.      */
    /*  Length of strings ( n1, n2 ) and the numbers of     */
    /*  0 paddings ( np1, np2, np3, np4 ) will be also set. */
    /*                                                      */
    /*      RETURN  non                                     */
    /*                                                      */
    /********************************************************/

	_PDAT          *stDatP   ;   /* data structure */
	double          dDat     ;   /* double size value */
	char           *cFmtP    ;   /* conversion specifier */

	{
	 DBL_LNG        tdDat    ;   /* union to check the value if NaN or inf */
	 int            iDatExp  ;   /* exponential part of dDat */
	 int            iFrNum   ;   /* number of characters needed to convert */
	 int            iDatSiz  ;   /* number of total output characters */
	 int            iExpCnt  ;   /* index of array for conversion of exponential part */
	 int            iCnt     ;   /* counter for loop */
	 char           CTrDatP[ DBL_DIG + 3 ];      /* array for conversion */
	 const static double  d10Exp[ ] = { 1e256, 1e128, 1e64, 1e32, 1e16, 1e8, 1e4, 1e2, 1e1, 1e0 };
	 const static int     iExp[ ]   = { 256, 128, 64, 32, 16, 8, 4, 2, 1, 0 };
	                             /* these two arrays are used to convert exponential part */

	 /* check the value */
	 tdDat._D = dDat;                            /* tdDat._D is double */
	 if( (tdDat.st._LL == MASK_EXP) && (tdDat.st._LH == 0) ) {
	                                             /* tdDat._D is inf */
	    memcpy( stDatP->ucOutDatP, "Inf", 3 );   /* set "Inf" to string A */
	    stDatP->iDatNum = 3;
	    stDatP->tdPadFlg = _PLO;                 /* need no 0 padding */
	    return;
	 } else if( (long)tdDat.st._LL >= MASK_EXP ) {   /* NaN */
	       memcpy( stDatP->ucOutDatP, "NaN", 3 );/* set "NaN" to string A */
	       stDatP->iDatNum = 3;
	       stDatP->iSigNum = 0;                  /* need no sign */
	       stDatP->tdPadFlg = _PLO;              /* need no 0 padding */
	       return;
	 }

	 /* divide into fractional and exponential part ... normalization */
	 iDatExp = 0;                                /* initialize exponential data */
	 if( dDat >= 10.0 ) {                        /* need to be scaled down */
	    for( iCnt = 0; iExp[ iCnt ] > 0; ++iCnt ) { /* 1e256 ~ 1e1 */
	       if( dDat >= d10Exp[ iCnt ] ) {        /* scale down with d10Exp */
	          dDat = dDat / d10Exp[ iCnt ];
	          iDatExp = iDatExp + iExp[ iCnt ];  /* renew exponential data */
	       }
	    }
	 } else if( (dDat > 0) && (dDat < 1.0) ) {   /* need to be scaled up */
	    for( iCnt = 0; iExp[ iCnt ] > 0; ++iCnt ) { /* 1e256 ~ 1e1 */
	       if( (*cFmtP == 'e') || (*cFmtP == 'E') ) {
	          if( dDat * d10Exp[ iCnt ] < 10.0 ) {  /* scale up with d10Exp */
	            dDat = dDat * d10Exp[ iCnt ];
	            iDatExp = iDatExp - iExp[ iCnt ];  /* renew exponential data */
	          }
	       } else {
	          if( dDat * d10Exp[ iCnt ] < 1.0 ) {  /* scale up with d10Exp */
	            dDat = dDat * d10Exp[ iCnt ];
	            iDatExp = iDatExp - iExp[ iCnt ];  /* renew exponential data */
                  }
	       }
	    }
	 }

	 /* conversion */
	 /* exponential notation */
	 if( (*cFmtP == 'e') || (*cFmtP == 'E') ) {
	    if( stDatP->iPrec <= DBL_DIG + 1 ) {     /* the precision is less than double type */
	       iFrNum = stDatP->iPrec + 1;           /* conversion length is iFrNum characters */
	    } else {
	       iFrNum = DBL_DIG + 2; 
	    }
	    iFrNum = _pfrtoch( dDat, &iDatExp, iFrNum, CTrDatP ); 
	                                             /* convert fractional part to a string */
	    
	    stDatP->ucOutDatP[ 0 ] = CTrDatP[ 0 ];   /* set the first character to string A */
	    iCnt = 1;
	    if( (iFrNum > 1) || (stDatP->tdBasFlg == _PHI) || (stDatP->iPrec >= 1) ) {
	                                             /* need decimal point */
	       stDatP->ucOutDatP[ iCnt ] = '.';      /* set decimal point */
	       ++iCnt;
	       memcpy( &(stDatP->ucOutDatP[ 2 ]), &CTrDatP[ 1 ], iFrNum - 1 );
	                                             /* set rest of string */
	       iCnt = iFrNum + 1;
	    }

	    stDatP->iDatNum = iCnt;                  /* n1 */
	    if( stDatP->iPrec > ( iFrNum -1 ) ) {    /* need 0 padding */
	       stDatP->iFltPad = stDatP->iPrec - ( iFrNum - 1 );  /* np2 */
	    }

	    stDatP->ucOutDatP[ iCnt ] = *cFmtP;      /* sign of exponential */
	    ++iCnt;
	    if( iDatExp >= 0 ) {                     /* exponent is bigger then 0 */
	       stDatP->ucOutDatP[ iCnt ] = '+';      /* set sign of exponential part */
	    } else {
	       stDatP->ucOutDatP[ iCnt ] = '-';
	       iDatExp = -iDatExp;
	    }
	    ++iCnt;

	    if( iDatExp >= 10 ) {    /* exponent should be expressed by more than 2 characters */
	       for( iExpCnt = 10; iDatExp > 0; --iExpCnt ) {
	          CTrDatP[ iExpCnt ] = iDatExp % 10 + '0';  /* get the least digit */
	          iDatExp = iDatExp / 10;                   /* shift 1 digit to the right */
	       }
	       memcpy( &(stDatP->ucOutDatP[ iCnt ]), &CTrDatP[ iExpCnt + 1 ], 10 - iExpCnt );
	                                                    /* set exponential number */
	       stDatP->iExpNum = 2 + ( 10 - iExpCnt );      /* n2 */
	    } else {
	       stDatP->ucOutDatP[ iCnt ] = '0';
	       ++iCnt;
	       stDatP->ucOutDatP[ iCnt ] = iDatExp + '0';
	       stDatP->iExpNum = 4;
	    }

	 } else {
	    
	 /* decimal notation */
	    if( iDatExp < 0 ) {                             /* less than 1.0 */
	       if( stDatP->iPrec <= -( iDatExp + 1 ) ) {    /* the value is too small */
	          iFrNum = 0;                               /* no need to convert */
	       } else if( stDatP->iPrec + (iDatExp + 1) <= DBL_DIG + 2 ) {
	                                                    /* the precision is less than double type */
	          iFrNum = stDatP->iPrec + (iDatExp + 1);   /* conversion length is iFrNum characters */
	       } else {
	          iFrNum = DBL_DIG + 2;
	       }

	       iFrNum = _pfrtoch( dDat, &iDatExp, iFrNum, CTrDatP ); 
	                                                    /* convert iFrNumber characters */
	       stDatP->ucOutDatP[ 0 ] = '0';                /* set the first character to string A */
	       iCnt = 1;
	       if( (iFrNum >= 1 ) || (stDatP->tdBasFlg == _PHI) || (stDatP->iPrec > 0) ) {
	                                                    /* need decimal point */
	          stDatP->ucOutDatP[ iCnt ] = '.';
	          ++iCnt;
	          memcpy( &(stDatP->ucOutDatP[2]), CTrDatP, iFrNum );
	                                                    /* set the rest of characters */
	       }

	       stDatP->iDatNum = iCnt;                      /* n1 */
	       stDatP->iExpNum = iFrNum;                    /* n2 */
	       if( stDatP->iPrec >= -( iDatExp + 1 ) ) {    /* np1 is depend on the exponent */
	          stDatP->iFltPad = -( iDatExp + 1 );
	       } else {
	          stDatP->iFltPad = stDatP->iPrec;
	       }
	       if( stDatP->iPrec > (stDatP->iExpNum + stDatP->iFltPad) ) {
	                                                    /* need 0 for precision */
	          stDatP->iPrecPad = stDatP->iPrec - stDatP->iExpNum -stDatP->iFltPad; /* np3 */
	       }

	    } else {                                        /* equal or more than 1.0 */
	       if( stDatP->iPrec < (DBL_DIG + 2) - (iDatExp + 1) ) {
	                                                    /* the precision is less than the decimal part */   
	          iFrNum = stDatP->iPrec + ( iDatExp + 1 ); /* conversion length */
	       } else {
	          iFrNum = DBL_DIG + 2;
	       }

	       iFrNum = _pfrtoch( dDat, &iDatExp, iFrNum, CTrDatP ); 
	                                                    /* convert iFrNumber characters */
	       if( iFrNum > iDatExp + 1 ) {                 /* there exist decimal part */
	          memcpy( stDatP->ucOutDatP, CTrDatP, iDatExp + 1 );
	                                                    /* set integral part */
	          stDatP->ucOutDatP[ iDatExp + 1 ] = '.';
	          memcpy( &(stDatP->ucOutDatP[ iDatExp + 2 ]), &CTrDatP[ iDatExp + 1 ]
	                  , iFrNum - iDatExp -1 );
	          stDatP->iDatNum = iDatExp + 1;            /* n1 */
	          stDatP->iExpNum = iFrNum - iDatExp;       /* n2 */
	          if( stDatP->iPrec > (iFrNum - iDatExp - 1) ){
	                                          /* the precision is more then the decimal part */
	             stDatP->iPrecPad = stDatP->iPrec - iFrNum + iDatExp + 1; /* np3 */
	          }

	       } else {                                     /* integer */
	          memcpy( stDatP->ucOutDatP, CTrDatP, iFrNum );
	          stDatP->iDatNum = iFrNum;                 /* n1 */
	          if( (stDatP->tdBasFlg == _PHI) || (stDatP->iPrec > 0) ) {
	                                                    /* need decimal point */
	             stDatP->ucOutDatP[ iFrNum ] = '.';
	             stDatP->iExpNum = 1;                   /* n2 */
	             stDatP->iPrecPad = stDatP->iPrec;      /* np3 */
	          }
	          if( (iDatExp + 1) > iFrNum ) {            /* least significant digit is 0 */
	             stDatP->iFltPad = iDatExp + 1 - iFrNum; /* np2 */
	          }
	       }
	    }
	 }

	 /* setting of 0 padding ... np1 */
	 if( stDatP->tdPadFlg == _PHI ) {                   /* 0 flag is specified */
	    if( stDatP->tdPosFlg == _PLO ) {                /* right justification is specified */
	       iDatSiz = stDatP->iSigNum + stDatP->iDatNum + stDatP->iFltPad
	                   + stDatP->iExpNum + stDatP->iPrecPad;
	       if( stDatP->iWid > iDatSiz ) {               /* number of characters is not reached 
	                                                           to the minimum field width */
	          stDatP->iSigPad = stDatP->iWid - iDatSiz; /* np1 */
	       }
	    }
	 }
	}



int
_pfrtoch( dFrac, iExpP, iChNum, cStorP )

    /********************************************************/
    /*                                                      */
    /*  The _pfrtoch function converts fractional part,     */
    /*  dFrac [ 1.0, 10.0 ), of normalized data to a string.*/ 
    /*  the string is stored in the address pointed to by   */
    /*  cStorP.                                             */ 
    /*  Converted string doesn't have decimal point.        */
    /*  To convert iChNum characters, the _pfrtoch function */
    /*  rounds off the (iChNum + 1)th digit.  If there is   */
    /*  a series of 0 at lowest position, it is cuted off.  */
    /*  In this case, return value ,which means the number  */
    /*  of converted characters, is less than iChNum.       */
    /*  If rounding off takes a figure up one place, only   */
    /*  "1" is set in the string, and exponential value     */
    /*  pointed to by iExpP is increased by 1, and the      */
    /*  _pfrtoch function returns 1.                        */
    /*                                                      */
    /*      RETURN  the number of converted characters      */
    /*                 If dFrac is 0.0, return value is 1.  */
    /*                 ( The string is "0". )               */
    /*                                                      */
    /********************************************************/

	double          dFrac    ;   /* normalized fraction */
	int            *iExpP    ;   /* exponential value */
	int             iChNum   ;   /* the number of characters to be converted */
	char           *cStorP   ;   /* the address, string to be stored in */

	{
	 int            iIndex   ;   /* the index to access store address */
	 int            iIntVal  ;   /* integer used to cut off decimal part */

	 /* conversion */
	 if( dFrac != 0 ) {                                 /* fraction is not 0 */
	    if( iChNum != 0 ) {                             /* need to convert */
	       for( iIndex = 0; iIndex < iChNum + 1; ++iIndex ) {
	                                                    /* convert iChNum + 1 characters */
	          iIntVal = (int)dFrac;
	          cStorP[ iIndex ] = iIntVal + '0';
	          dFrac = 10.0 * ( dFrac - (double)iIntVal );
	       }
	       --iIndex;                                    /* set index to last character */
	       /* bug fix 2001.03.23 T.Tazaki */
	       if( ( (iChNum - (*iExpP+1)) <= DBL_DIG ) &&
		   ( ( *iExpP+1 ) <= DBL_DIG ) ){
		       if( iIndex > DBL_DIG ){
			       	iIndex = DBL_DIG;
			   }
			}
	       /* bug fix 2001.03.23 T.Tazaki */
	    } else {
	       return( 0 );
	    }
	 } else {
	    *cStorP = '0';
	    return( 1 );
	 }

	 /* rounding off */
	 if( cStorP[ iIndex ] >= '5' ) {                    /* rounding up */
	    do {
	       if( iIndex == 0 ) {                          /* take a figure up one place */
	          cStorP[ iIndex ] = '1';                   /* string is "1" */
	          *iExpP = *iExpP + 1;
	          return( 1 );
	       } else {
	          cStorP[ iIndex ] = '0';                   /* clear present place */
	          --iIndex;
	          cStorP[ iIndex ] = cStorP[ iIndex ] + 1;  /* round up */
	       }
	    } while( cStorP[ iIndex ] > '9' );              /* need to round up */

	 } else {
	 /* cut off 0 at lowest position */
	    cStorP[ iIndex ] = '0';
	    do {
	       --iIndex;
	    } while( cStorP[ iIndex ] == '0' );
	 }
	 return( iIndex + 1 );
	}
	
